Skip to content

fix(iOS): omit state when additionalParameters.state is null - #1125

Open
shashank-bhatotia wants to merge 1 commit into
FormidableLabs:mainfrom
shashank-bhatotia:fix/ios-nsnull-state
Open

fix(iOS): omit state when additionalParameters.state is null#1125
shashank-bhatotia wants to merge 1 commit into
FormidableLabs:mainfrom
shashank-bhatotia:fix/ios-nsnull-state

Conversation

@shashank-bhatotia

Copy link
Copy Markdown

Description

On iOS, passing state: null in additionalParameters builds an authorization request whose
state is NSNull. AppAuth then rejects the response:

State mismatch, expecting <null> but got (null) in authorization response

<null> is NSNull's description and (null) is nil's, so the message shows the request
carried NSNull while the response carried nothing.

The cause is in ios/RNAppAuth.m:

state: additionalParameters[@"state"] ? additionalParameters[@"state"] : [[self class] generateState]

JS null bridges to NSNull. NSNull is a real object and therefore truthy, so the ternary
takes the left branch and assigns it as the state.

Android already handles this. RNAppAuthModule.java reads params into a HashMap, which
permits null values, so containsKey("state") is true and it calls setState(null), omitting
the parameter. CONTRIBUTING asks that behavior be replicated across both platforms, so this
brings iOS to what Android already does.

Behavior after the change:

Since null was not previously a legal value, this also updates index.d.ts (state?: string | null on BuiltInParameters) and the additionalParameters docs, so the opt-out is declared
rather than implied.

One caveat now in the docs: omitting state is only safe against providers that do not invent
one. If a provider returns a state that was never sent, validation fails from the other
direction. Android behaves the same way, so parity holds.

Deliberately out of scope

nonce on the line above has the same shape. I left it alone because the semantics differ: a
documented opt-out already exists in useNonce: false, so "null means omit" would add a second
switch that can contradict the first. Happy to add it if you would rather have the consistency.

logout forwards additionalParameters verbatim to OIDEndSessionRequest, which appends its
own state, so a caller-supplied state is sent twice there. Same class of issue as #974 but on a
different path, so not folded in here.

Steps to verify

There is no iOS test target in this repo, so this is a simulator check against a provider that
does not echo state back. Run examples/demo:

  1. authorize with additionalParameters: { state: null }. Before this change the flow fails
    with State mismatch, expecting <null> but got (null). After it, the authorization URL
    carries no state parameter and the flow completes.
  2. authorize with no state key. A random state is still sent and echoed back, unchanged
    from today.
  3. authorize with additionalParameters: { state: 'abc123' }. That exact value is sent.

yarn lint passes. yarn test passes, though the JS suite has no coverage of this path, so it
is not evidence for the fix itself.

@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

@shashank-bhatotia is attempting to deploy a commit to the Nearform Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 04ab6b2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
react-native-app-auth Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant